package edu.xidian.onlinedocument.service;

import edu.xidian.onlinedocument.entity.OperationData;
import edu.xidian.onlinedocument.handler.excpetions.custom.CustomException;
import edu.xidian.onlinedocument.repository.DocumentJPARepository;
import edu.xidian.onlinedocument.repository.OperationDataJPARepository;
import edu.xidian.onlinedocument.views.ResultCode;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

/**
 * Operation相关业务
 * 主要涉及文档操作的业务，主要是针对某个文档的操作序列的增、删、查
 */
@Service
public class OperationService {
    private final CustomDraw customDraw;

    private final OperationDataJPARepository operationDataJPARepository;

    private final DocumentService documentService;

    @Autowired
    OperationService(OperationDataJPARepository operationDataJPARepository,
                     DocumentService documentService,
                     CustomDraw customDraw) {
        this.operationDataJPARepository = operationDataJPARepository;
        this.documentService = documentService;
        this.customDraw = customDraw;
    }

    /**
     * 查询所有operation，测试用
     * @return List<OperationData>
     */
    public List<OperationData> getAllOperationData() {
        return operationDataJPARepository.findAll();
    }

    /**
     * 根据文档id查询该文档的一系列操作
     * @param docId 文档id
     * @return List<OperationData>
     */
    public List<OperationData> getOperationDataByDocId(Integer docId) {
        customDraw.checkDocId(docId);
        this.checkIsDocIdExist(docId);
        return operationDataJPARepository.findAllByDocIdOrderByOpIdAsc(docId);
    }

    /**
     * 根据文档id和版本号查询该文档的某版本操作
     * @param docId 文档id
     * @param opVersion 文档版本
     * @return List<OperationData>
     */
    public List<OperationData> getOperationDataByDocIdAndOpVersion(Integer docId, Integer opVersion) {
        customDraw.checkDocId(docId);
        customDraw.checkVersion(opVersion);
        this.checkIsDocIdExist(docId);
        this.checkIsOpVersionExist(docId, opVersion);
        return operationDataJPARepository.findAllByDocIdAndOpRevisionOrderByOpIdAsc(docId, opVersion);
    }

    /**
     * 向数据库添加一个操作
     * @param docId 文档id
     * @param opVersion 操作版本
     * @param opName 操作名
     * @param opLength 操作作用的长度
     * @param opValue 操作内容（可为null）
     * @return OperationData
     */
    @Transactional(rollbackFor = {RuntimeException.class, Error.class})
    public OperationData saveOneOperation(Integer docId, Integer opVersion, String opName, Integer opLength, String opValue) {
        OperationData operationData = new OperationData(docId, opVersion, opName, opLength, opValue);
        return operationDataJPARepository.saveAndFlush(operationData);
    }

    /**
     * 向数据库添加一个操作
     * @param operationData 一个操作
     * @return OperationData
     */
    @Transactional(rollbackFor = {RuntimeException.class, Error.class})
    public OperationData saveOneOperation(OperationData operationData) {
        return operationDataJPARepository.saveAndFlush(operationData);
    }

    /**
     * 向数据库添加一系列的操作
     * @param operationDataList 操作列表
     * @return List<OperationData>
     */
    @Transactional(rollbackFor = {RuntimeException.class, Error.class})
    public List<OperationData> saveSerialOperations(List<OperationData> operationDataList) {
        return operationDataJPARepository.saveAllAndFlush(operationDataList);
    }

    public boolean existsOperationData(Integer docId, Integer opRevision) {
        return operationDataJPARepository.existsOperationDataByDocIdAndOpRevision(docId, opRevision);
    }

    public int deleteOperationDataByDocIdAndRevision(Integer docId, Integer opRevision) {
        checkIsOpVersionExist(docId, opRevision);
        int res = operationDataJPARepository.deleteAllByDocIdAndOpRevision(docId, opRevision);
        return res;
    }

    /**
        以下为组件方法
     */

    private void checkIsDocIdExist(int docId) {
        if(!documentService.existsByDocId(docId)) {
            if(!documentService.existsByDocIdAndIsNotDelete(docId)) {
                throw new CustomException(ResultCode.DOCUMENT_FLAG_IS_DELETE);
            }
            else {
                throw new CustomException(ResultCode.DOCUMENT_NOT_EXIST);
            }
        }
    }

    private void checkIsOpVersionExist(int docId, int opVersion) {
        if(!operationDataJPARepository.existsOperationDataByDocIdAndOpRevision(docId, opVersion)) {
            throw new CustomException(ResultCode.OPERATION_VERSION_NOT_EXIST);
        }
    }
}
